home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
scope
/
101-125
/
scopedisk111
/
ff15
/
ff.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-19
|
16KB
|
579 lines
/*
FileFind Amiga Version 1.5
FF will search all directories on a filing device for occurances of a
particular file. Supports both AmigaDOS and MS-DOS wildcards
and is PURE - can be made resident.
History:
Version 1.1: Now will support the MS-DOS wildcard characters: "*" and "?"
Also: smaller code and a little quicker execution.
Version 1.2: Uses AmigaDOS' Lock(), Examine() & ExNext() instead of
Lattice's dfind() & dnext(). AmigaDOS' routines are
much faster and can be used recursively so it is not
neccesary to use the heap to make a list of directories.
Lattice's stcpm() is used to compare filenames that are
found to the user-supplied wildcard. If stcpm() says that
a filename matches, then the name is displayed. This
change increases the speed of this routine by an average
of 55%!!! One additional modification allows the user to
specify a directory to look in. This effectively defines
a branch of the directory tree to search in, rather than
always starting at the root and scanning all directories
on the disk. 4-10-88 Finished.... 4-22-88
Version 1.3: Added Ctrl-CDEF handling. Re-compiled to take advantage of
Lattice Version 5.02 direct shared library calls - this
eliminates the need to link in the amiga.lib stub routines
thereby shortening the executable code size (as well as
providing a tiny speed increase). Added ANSI-C prototyping
function calls. Pruned the code a little more. Took advantage
of Lattice 5.02 registerized parameters for some functions
and register type auto variables within functions. Removed all
global variables to allow for pure code (Resident-able). Compiled
with stack checking turned off (-v) and "merge duplicate strings"
on (-cs) for smaller code size. Added printing of path names
that are being searched. Added support for quoted arguments
which may contain spaces.
Finished: 07-26-89
Version 1.4: Replaced Lattice's slightly inappropriate pattern matching
routines with one of my own. It supports the following wildcard
characters:
? - matches one of any character.
#x - matches one or more occurances of "x", which can be
any valid character.
* - matches any number of any characters.
#? - (really an instance of "#x") works same as "*".
My routine was written specifically for filename pattern matching
which makes it more appropriate for use in this program. It is
a little larger than Lattice's but it appears to be faster, and
it behaves like a filename wildcard pattern matching routine
is supposed to, unlike Lattice's which is really an all-purpose
regular expression parser. For example, with Lattice's routine,
if the user entered "FF foo", Lattice would actually match "foo*",
which probably not what the user really wanted to see. My routine
would literally match "foo" if that is what was entered, or "foo*"
if that is what was entered.
Finished: 08/12/89
Version 1.5: Added the Quiet (-q) and the Verbose (-v) switches.
Corrected potential problem in the SKIP_NON_WHITE() macro which
did not look-out for the end of the string. Changed MAX_PATH_LEN
to 257 to be consistant with AmigaDOS' path length limit of 256
characters - no room here for artificial constraints!
Finished: 10/23/89
Copyright © 1988, 1989 Ray Lambert
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <dos.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/memory.h>
#include <proto/dos.h>
#include <proto/exec.h>
#define VERSION "1.5 (pure!)\n"
#define MAX_PATH_LEN 257
#define SKIP_WHITE(s) while(*(s)==' ') (s)++
#define SKIP_NON_WHITE(s) while((*(s)!=' ')&&(*(s)!='\0')) (s)++
#define CLREOL conwrite("K")
UBYTE bequiet; /* this global data is ok with Lattice's cres.o residentable
startup module */
/****/
char * __asm strsrch(register __a0 char *str, register __a1 char *sstr)
{
register char *a;
register char *b;
register char *z;
int slen=strlen(str);
int sslen=strlen(sstr);
if (sslen>slen) return(NULL);
z=(char *)(str+(slen-sslen+1));
for(; str<=z; str++)
{
if (*str==*sstr)
{
a=str;
b=sstr;
do
{
a++;
b++;
}
while( (*b) && (*b==*a) );
if (!*b) return(str); /* end of search string reached - its a match! */
}
}
return(NULL);
}
/****/
int __asm wcmatch(register __a0 char *name, register __a1 char *pattern)
{
register char *wc;
register char *ss;
register char *a;
register char *b;
register char *temp;
register int result=-1;
/* So you say goto's are a no-no eh? Well let's see you code the
following more efficiently... */
temp=malloc(strlen(name)+1);
if (!temp) goto wcabort1;
wc=strdup(pattern);
if (!wc) goto wcabort2;
strupr(wc);
ss=strdup(name);
if (!ss) goto wcabort3;
strupr(ss);
/*
I know the following is cheating a little but for the sake of simplicity
I'm gonna do it anyway! Any occurance of "#?" in the pattern will be
changed to "*". The two patterns do the same thing, and now we'll
only have to parse for one of them.
*/
do
{
a=strsrch(wc,"#?");
if (a)
{
*a='*';
a++;
b=(a+1);
while(*b)
{
*a=*b;
a++;
b++;
}
*a='\0';
}
}
while(a);
/* now to get down to work... */
a=wc; /* "a" tracks the wildcard pattern */
b=ss; /* "b" tracks the source string (filename?) */
for(; result==-1; )
{
/* check for premature end of source string */
if ( (*b=='\0') && (*a!='\0') )
{ /* if end of source string but only one char left in
pattern and its a '*' then it is a match */
if ( (*a=='*') || (*(a+1)=='\0') )
{
result=1; /* a match */
}
else
{
result=0; /* no match */
}
continue;
}
/* parse next wildcard character */
switch(*a)
{
case '\0': /* end of pattern string */
{
if (*b=='\0')
{
result=1; /* exact match */
continue;
}
result=0; /* no match */
continue;
}
case '?':
/* matches any character */
{
a++;
b++;
break;
}
case '#':
/* matches any number of occurances of the following character */
{
a++;
while( (*b) && (*b==*a) ) b++;
a++;
continue;
}
case '*':
/* matches any number of occurances of any character(s) */
{
register char *c;
a++;
/* is "*" the last character in pattern? If so then match */
if (!*a)
{
result=1; /* match */
continue;
}
/* extract the sub-string existing after the "*" */
c=temp;
while(!strchr("?#*",*a))
{
*c=*a;
c++;
a++;
}
*c='\0';
if (!*temp) /* no sub-string exists - ignore this wc char */
{
continue;
}
/* locate the extracted sub-string in the source string */
c=strsrch(b,temp);
if (!c)
{
result=0; /* no match */
continue;
}
/* at this point we have:
a: points to first char beyond sub-string following "*" in pattern
b: points to chars to be matched to "*" (to be tossed)
c: points to temp sub-string in search string (beyond b)
we must: advance b beyond the substring pointed to by c
*/
b=(char *)(c+strlen(temp));
continue; /* and that's it! */
}
default: /* must match exactly! (another easy one...) */
{
if (*a!=*b)
{
result=0; /* no match */
continue;
}
a++;
b++;
break;
}
}
}
free(ss);
wcabort3:
free(wc);
wcabort2:
free(temp);
wcabort1:
return(result);
}
/****/
void __asm conwrite(register __a0 char *str)
{
Write(Output(),str,strlen(str));
}
/****/
void __asm conwrite_int(register __d0 int num)
{
char str[10];
register int i;
register char *p=str;
/* Find beginning divisor */
for(i=10000; ( (i>num) && (i>1) ); i/=10);
do
{
*p=(char)((num/i)+'0');
num%=i;
i/=10;
p++;
}
while(i>=1);
*p='\0';
conwrite(str);
}
/****/
int chk4brk(void)
{
if ( SetSignal(0L,0L) &
( SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D |
SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F )
) return(1);
return(0);
}
/****/
void __asm report_searching( register __a0 char *root,
register __d0 int level,
register __a1 char *mask )
{
if (bequiet) return;
CLREOL;
conwrite("Searching: ");
conwrite(root);
if (level>0) conwrite("/");
conwrite(mask);
conwrite("\x0d"); /* move cursor to column 1 */
}
/****/
int __asm dtree( register __a0 char *root,
register __a1 char *mask,
register __d0 int level )
{
char temp_str[MAX_PATH_LEN];
register int cnt=0;
register BPTR lock;
register struct FileInfoBlock *info;
register int brk=0;
if ( (lock=Lock(root,ACCESS_READ))==NULL ) return(0);
info=(struct FileInfoBlock *)
AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR);
/* AllocMem() is used to guarantee long-word alignment */
if (!info)
{
UnLock(lock);
conwrite("33;42m Memory is low! 0m\n");
return(0);
}
if (!bequiet) report_searching(root,level,mask);
if (!Examine(lock,info))
{
UnLock(lock);
FreeMem(info,sizeof(struct FileInfoBlock));
return(0);
}
while( (brk==0) && (ExNext(lock,info)!=0) )
{
if (brk=chk4brk()) continue;
strcpy(temp_str,root);
if (level>0) strcat(temp_str,"/");
strcat(temp_str,info->fib_FileName);
if (info->fib_DirEntryType>0)
{ /* it's a directory - scan it */
register int result;
level++;
result=dtree(temp_str,mask,level);
level--;
if (result==-1)
{
brk=1;
continue;
}
cnt+=result;
}
else
{ /* it is a normal file - compare it */
strupr(info->fib_FileName);
if (wcmatch(info->fib_FileName,mask))
{
if (!bequiet) CLREOL;
conwrite("33mFound: ");
conwrite(temp_str);
conwrite("\n0m");
if (!bequiet) report_searching(root,level,mask);
cnt++;
}
}
}
UnLock(lock);
FreeMem(info,sizeof(struct FileInfoBlock));
return( (int)((brk!=0)?(-1):(cnt)) );
}
/****/
void usage(void)
{
conwrite("\nUsage: FF [-q] [-v] [DRIVE:][PATH/]FILENAME [...]\n\n");
conwrite(" [-q] = Quiet mode - supresses \"searching...\" messages\n");
conwrite(" [-v] = Verbose mode - opposite of \"Quiet\" (default)\n");
conwrite(" [DRIVE:] = Optional drive to scan\n");
conwrite(" [PATH/] = Optional path to begin scan at\n");
conwrite(" FILENAME = File to search for (wildcards allowed)\n");
conwrite(" [...] = Optional multiple additional arguments\n\n");
exit(5);
}
/****/
char * __regargs strdcpy(char *to, char *from, char delimiter)
{
while( (*from!=delimiter) && (*from!='\0') )
{
*to=*from;
to++;
from++;
}
*to='\0';
if (*from==delimiter) from++;
return(from);
}
/****/
void _main(char *args)
{
register char *ptr;
register int match_cnt;
char
drive[MAX_PATH_LEN],
file_mask[MAX_PATH_LEN];
conwrite("\n33;40mFileFind Amiga! Version ");
conwrite(VERSION);
conwrite("0mCopyright © 1988, 1989 by Ray Lambert\n");
bequiet = 0; /* initialize to Verbose mode */
/* Change terminating newline to a NULL */
ptr=(char *)(args+strlen(args)-1);
if (*ptr=='\n') *ptr='\0';
/* Skip over command "FF " */
SKIP_WHITE(args);
SKIP_NON_WHITE(args);
/* check for no args */
SKIP_WHITE(args);
if (!*args) usage();
conwrite("(Ctrl-C to abort)\n\n");
/* process all args */
do
{
/* get next arg */
if (*args=='-') /* a switch */
{
args++;
switch(toupper(*args))
{
case 'Q': /* quiet switch */
{
bequiet = 1;
conwrite("32;40m(Quiet mode enabled)0m\n");
break;
}
case 'V': /* verbose switch */
{
bequiet = 0;
conwrite("32;40m(Verbose mode enabled)0m\n");
break;
}
}
SKIP_NON_WHITE(args);
SKIP_WHITE(args);
continue;
}
if (*args=='\"') /* quoted argument */
{ /* copy till closing quote or null */
args=strdcpy(drive,(++args),'\"');
}
else /* normal argument */
{ /* copy till space or null */
args=strdcpy(drive,args,' ');
}
/* Skip over leading spaces for next pass */
SKIP_WHITE(args);
/* Check for user drive spec */
ptr=strchr(drive,':');
if (ptr) /* Drive was supplied by user */
{
/* Get pointer to last xter (actually to null) */
while(*ptr!='\0') ptr++;
/* Find beginning of file mask */
while( (*ptr!='/') && (*ptr!=':') ) ptr--;
/* copy file mask to "file_mask" variable */
strcpy(file_mask,(ptr+1));
/* truncate file mask from "drive" variable */
*(ptr+1)='\0';
/* don't forget to trunc the "/" */
if (*ptr=='/') *ptr='\0';
}
else /* Get drive from system */
{
strcpy(file_mask,drive);
if (getcd(0,drive)!=0) exit(50); /* die silently */
/* Cut path off - we only want the volume name */
ptr=strchr(drive,':');
if (ptr) *(++ptr)='\0';
}
/* be a little user friendly */
conwrite("\nSearching for file \"");
conwrite(file_mask);
conwrite("\" on drive \"");
conwrite(drive);
conwrite("\"\n\n");
/* actually do the search */
ptr=strchr(drive,':');
match_cnt=dtree(drive,file_mask, ( (*(++ptr)!='\0') ? (1) : (0) ) );
/* clear the last searching message */
if (!bequiet) CLREOL;
/* process the result */
switch(match_cnt)
{
case -1: /* a ctrl-? break occured */
{
conwrite("**break\n\n");
exit(0);
}
case 0:
{
conwrite("No matches found.\n\n");
break;
}
default:
{
conwrite("\nFound ");
conwrite_int(match_cnt);
conwrite(" match");
conwrite( ( (match_cnt==1) ? (".\n\n") : ("es.\n\n") ) );
break;
}
}
}
while(*args!='\0');
}